package com.tcm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tcm.config.AppProperties;
import com.tcm.entity.*;
import com.tcm.entity.bo.BattleRoomCacheBo;
import com.tcm.entity.bo.BattleUserCacheBo;
import com.tcm.entity.dto.BattleItemInfoDto;
import com.tcm.entity.resp.PageR;
import com.tcm.entity.vo.BattleDetailResp;
import com.tcm.entity.vo.BattleHisDetailResp;
import com.tcm.entity.vo.BattleListResp;
import com.tcm.exception.BattleWsHandleException;
import com.tcm.exception.EntityInvalidException;
import com.tcm.mapper.*;
import com.tcm.service.BattleService;
import com.tcm.service.ImageService;
import com.tcm.service.RoleService;
import com.tcm.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Guqier
 * @description 针对表【ts_battle(对战记录表)】的数据库操作Service实现
 * @createDate 2023-09-24 14:34:31
 */
@Service
@RequiredArgsConstructor
public class BattleServiceImpl extends ServiceImpl<BattleMapper, Battle>
        implements BattleService {

    private final BattleDetailMapper battleDetailMapper;

    private final BattleUserMapper battleUserMapper;

    private final UserService userService;

    private final ImageService imageService;

    private final BattleItemMapper battleItemMapper;

    private final RoleService roleService;

    private final TeacherMapper teacherMapper;

    /**
     * 保存对战记录
     * @param userCacheBo 用户缓存信息
     * @param roomCacheBo 房间缓存信息
     * @param isComplete  是否完成
     */
    @Override
    public void saveBattle(BattleUserCacheBo userCacheBo, BattleRoomCacheBo roomCacheBo, Boolean isComplete) {
        Long userId = userCacheBo.getUserId();
        // 保存对战结果到数据库
        Battle battle = this.getById(roomCacheBo.getBattleId());
        if (Objects.isNull(battle)) {
            // 如果对战记录不存在则创建
            battle = new Battle();
            battle.setId(roomCacheBo.getBattleId());
            battle.setResultType(1);
            if (isComplete) {
                battle.setWinnerAccount(userCacheBo.getAccount());
            }
            battle.setStartTime(new Date());// 这里暂时不做保存
            battle.setEndTime(new Date());
            battle.setCreateUser(userId);
            battle.setUpdateUser(userId);
            battle.setNumberSize(roomCacheBo.getMaxNum());
            if (!this.save(battle)) {
                throw new BattleWsHandleException(userId, "保存对战记录失败");
            }
        } else {
            if (isComplete && Objects.isNull(battle.getWinnerAccount())) {
                battle.setWinnerAccount(userCacheBo.getAccount());
                if (!this.updateById(battle)) {
                    throw new BattleWsHandleException(userId, "保存对战记录失败");
                }
            }
        }
        // 保存对战用户
        if (battleUserMapper.selectCount(new LambdaQueryWrapper<BattleUser>().eq(BattleUser::getBattleId, battle.getId()).eq(BattleUser::getAccount, userCacheBo.getAccount())) == 0) {
            BattleUser user = new BattleUser();
            user.setBattleId(battle.getId());
            user.setAccount(userCacheBo.getAccount());
            user.setTotalScore(userCacheBo.getScore());
            user.setConsumeTime(userCacheBo.getConsumeTime());
            user.setCreateUser(userId);
            user.setUpdateUser(userId);
            List<BattleRoomCacheBo.Member> members = roomCacheBo.getMembers();
            user.setIsExit(1);
            members.stream().filter(member -> member.getUserId().equals(userCacheBo.getUserId())).findFirst().ifPresent(member -> user.setIsExit(member.getIsExit() ? 1 : 0));

            if (battleUserMapper.insert(user) != 1) {
                throw new BattleWsHandleException(userId, "保存对战用户失败");
            }
            // 保存对战详细
            Battle finalBattle = battle;
            List<BattleDetail> battleDetails = userCacheBo.getTopics().stream().map(battleTopicBo -> {
                BattleDetail detail = new BattleDetail();
                detail.setBattleId(finalBattle.getId());
                detail.setAccount(user.getAccount());
                detail.setItemId(battleTopicBo.getId());
                detail.setItemType(battleTopicBo.getType());
                detail.setAns(battleTopicBo.getAns());
                detail.setScore(battleTopicBo.getScore());
                detail.setCreateUser(userId);
                detail.setUpdateUser(userId);
                return detail;
            }).collect(Collectors.toList());
            for (BattleDetail battleDetail : battleDetails) {
                if (battleDetailMapper.insert(battleDetail) != 1) {
                    throw new BattleWsHandleException(userId, "保存对战详细信息失败");
                }
            }
        }
    }

    /**
     * 获取对战记录
     * @param account  当前用户账号
     * @param pageNum  当前页号
     * @param pageSize 页面大小
     * @return 对战记录列表
     */
    @Override
    public PageR<BattleListResp> getBattleList(String account, Integer pageNum, Integer pageSize) {
        Page<BattleUser> page = new Page<>(pageNum, pageSize);
        page.addOrder(OrderItem.desc("create_time"));
        // 查询对战记录
        battleUserMapper.selectPage(page, new LambdaQueryWrapper<BattleUser>()
                .eq(BattleUser::getAccount, account));

        // 获取所有对战ID
        List<BattleUser> battleUsers = page.getRecords();
        List<Long> ids = battleUsers.stream().map(BattleUser::getBattleId).collect(Collectors.toList());
        // 查询答题记录
        List<BattleDetail> battleDetails = battleDetailMapper.selectList(
                new LambdaQueryWrapper<BattleDetail>()
                        .eq(BattleDetail::getAccount, account)
                        .in(!CollectionUtils.isEmpty(ids), BattleDetail::getBattleId, ids)
                        .apply(CollectionUtils.isEmpty(ids), "1 != 1"));

        // 查询对战记录
        List<Battle> battles = this.list(new LambdaQueryWrapper<Battle>()
                .in(!CollectionUtils.isEmpty(ids), Battle::getId, ids)
                .apply(CollectionUtils.isEmpty(ids), "1 != 1"));
        // 构造结果集
        PageR<BattleListResp> pageR = new PageR<>();
        BeanUtils.copyProperties(page, pageR, "records");
        List<BattleListResp> collect = battleUsers.stream().map(battleUser -> {
            BattleListResp resp = new BattleListResp();
            battles.stream().filter(battle -> battle.getId().equals(battleUser.getBattleId())).findFirst().ifPresent(battle -> {
                List<BattleUser> thisBattleUsers = battleUserMapper.selectList(
                        new LambdaQueryWrapper<BattleUser>()
                                .eq(BattleUser::getBattleId, battleUser.getBattleId())
                                .orderByAsc(BattleUser::getConsumeTime));
                int rank = thisBattleUsers.stream().map(BattleUser::getAccount).collect(Collectors.toList()).indexOf(account);
                resp.setRank(rank + 1);
                resp.setId(battle.getId());
                resp.setIsWinner(account.equals(battle.getWinnerAccount()));
                resp.setRoomMaxNum(battle.getNumberSize());
                resp.setTime(battle.getCreateTime());

            });
            resp.setConsumeTime(battleUser.getConsumeTime());
            // 查找答题数量
            List<BattleDetail> userDetails = battleDetails.stream().filter(battleDetail -> battleDetail.getBattleId().equals(battleUser.getBattleId())).collect(Collectors.toList());
            resp.setItemTotalNum(userDetails.size());
            List<BattleDetail> correctDetails = userDetails.stream().filter(battleDetail -> battleDetail.getScore().equals(AppProperties.BATTLE_ITEM_SCORE)).collect(Collectors.toList());
            resp.setItemCorrectNum(correctDetails.size());
            return resp;
        }).collect(Collectors.toList());
        pageR.setRecords(collect);
        return pageR;
    }

    /**
     * 获取对战场次和最短耗时
     * @param account 用户账号
     * @return 对战场次和最短耗时
     */
    @Override
    public Map<String, Integer> getBattleCountAndMinConsumeTime(String account) {
        Map<String, Integer> map = new HashMap<>();
        List<BattleUser> battleUsers = battleUserMapper.selectList(new LambdaQueryWrapper<BattleUser>().eq(BattleUser::getAccount, account));
        Optional<BattleUser> min = battleUsers.stream().min(Comparator.comparing(BattleUser::getConsumeTime));
        map.put("count", battleUsers.size());
        map.put("minConsumeTime", min.isPresent() ? min.get().getConsumeTime() : -1);
        return map;
    }

    /**
     * 获取对战记录详细
     * @param id      对战记录ID
     * @param account 当前登录用户ID
     * @return 对战详细响应封装类
     */
    @Override
    public BattleHisDetailResp getBattleDetail(Long id, String account) {
        // 获取对战信息
        Battle battle = this.getById(id);
        if (Objects.isNull(battle)) {
            throw new EntityInvalidException("对战记录不存在");
        }

        // 获取对战成员信息
        List<BattleUser> battleUsers = battleUserMapper.selectList(
                new LambdaQueryWrapper<BattleUser>()
                        .eq(BattleUser::getBattleId, battle.getId())
                        .orderByAsc(BattleUser::getConsumeTime));
        // 获取当前用户对战详细
        List<BattleDetail> battleDetails = battleDetailMapper.selectList(
                new LambdaQueryWrapper<BattleDetail>()
                        .eq(BattleDetail::getBattleId, battle.getId()));

        // 构造成员信息
        List<BattleDetailResp> detailResps = battleUsers.stream().map(battleUser -> {
            BattleDetailResp resp = new BattleDetailResp();
            User user = userService.getUserByAccount(battleUser.getAccount());
            resp.setAccount(user.getAccount());
            resp.setUserId(String.valueOf(user.getId()));
            resp.setNickname(user.getNickname());
            resp.setIsFinished(true);
            resp.setRank(battleUsers.indexOf(battleUser) + 1);
            resp.setIsExit(battleUser.getIsExit() == 1);
            resp.setScore(battleUser.getTotalScore());
            resp.setSeconds(battleUser.getConsumeTime());
            List<BattleDetail> details = battleDetails.stream().filter(battleDetail -> battleDetail.getAccount().equals(user.getAccount())).collect(Collectors.toList());
            resp.setTotalNum(details.size());
            resp.setCorrectNum((int) details.stream().filter(battleDetail -> battleDetail.getScore().equals(AppProperties.BATTLE_ITEM_SCORE)).count());
            Optional.ofNullable(user.getAvatar()).ifPresent(imageId -> resp.setAvatarUrl(imageService.getImageById(imageId).getRemoteFileUrl()));
            return resp;
        }).collect(Collectors.toList());

        // 构造题目信息
        List<BattleDetail> detailList = battleDetails.stream().filter(battleDetail -> battleDetail.getAccount().equals(account)).collect(Collectors.toList());
        List<Long> itemIds = detailList.stream().map(BattleDetail::getItemId).collect(Collectors.toList());
        List<BattleItemInfoDto> battleItemInfoDtos = battleItemMapper.selectBattleItemAllInfoBatchById(itemIds);
        List<BattleHisDetailResp.Topic> topics = battleItemInfoDtos.stream().map(battleItemInfoDto -> {
            if (Objects.isNull(battleItemInfoDto)) {
                throw new EntityInvalidException("题目不存在");
            }
            BattleHisDetailResp.Topic topic = new BattleHisDetailResp.Topic();
            topic.setId(battleItemInfoDto.getId());
            topic.setType(battleItemInfoDto.getType());
            detailList.stream().filter(battleDetail -> battleDetail.getItemId().equals(battleItemInfoDto.getId())).findFirst().ifPresent(battleDetail -> {
                topic.setScore(battleDetail.getScore());
                topic.setAns(battleDetail.getAns());
            });
            topic.setContent(battleItemInfoDto.getContent());
            topic.setSubContent(battleItemInfoDto.getSubContent());

            // 获取题目选项
            List<BattleItemDetail> details = battleItemInfoDto.getDetails();
            List<BattleHisDetailResp.Topic.Option> options = details.stream().map(detail -> new BattleHisDetailResp.Topic.Option(detail.getOption(), detail.getContent())).collect(Collectors.toList());
            topic.setOptions(options);

            // 获取题目答案
            topic.setTruthAns(battleItemInfoDto.getAns());
            topic.setIsMultiple(battleItemInfoDto.getAns().length() > 1);
            topic.setDescribe(battleItemInfoDto.getDescribe());
            return topic;
        }).collect(Collectors.toList());
        /*
        List<BattleHisDetailResp.Topic> topics = detailList.stream().map(battleDetail -> {
            // 获取题目信息
            BattleItemInfoDto battleItemInfoDto = battleItemMapper.selectBattleItemAllInfoById(battleDetail.getItemId());
            if (Objects.isNull(battleItemInfoDto)) {
                throw new EntityInvalidException("题目不存在");
            }
            BattleHisDetailResp.Topic topic = new BattleHisDetailResp.Topic();
            topic.setId(battleItemInfoDto.getId());
            topic.setType(battleItemInfoDto.getType());
            topic.setScore(battleDetail.getScore());
            topic.setContent(battleItemInfoDto.getContent());
            topic.setSubContent(battleItemInfoDto.getSubContent());

            // 获取题目选项
            List<BattleItemDetail> details = battleItemInfoDto.getDetails();
            List<BattleHisDetailResp.Topic.Option> options = details.stream().map(detail -> new BattleHisDetailResp.Topic.Option(detail.getOption(), detail.getContent())).collect(Collectors.toList());
            topic.setOptions(options);

            // 获取题目答案
            topic.setAns(battleItemInfoDto.getAns());
            topic.setIsMultiple(battleItemInfoDto.getAns().length() > 1);
            topic.setDescribe(battleItemInfoDto.getDescribe());
            return topic;
        }).collect(Collectors.toList());
         */
        BattleHisDetailResp resp = new BattleHisDetailResp();
        resp.setDetails(detailResps);
        resp.setTopics(topics);
        return resp;
    }

    @Override
    public PageR<BattleListResp> getBattleListByTeacher(Integer pageNum, Integer pageSize, String account, Long currUserId, String currAccount) {
        Page<BattleUser> page = new Page<>(pageNum, pageSize);
        page.addOrder(OrderItem.desc("create_time"));

        // 构造查询条件
        LambdaQueryWrapper<BattleUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StringUtils.hasText(account), BattleUser::getAccount, account);
        if (!roleService.isAdministrator(currUserId)) {// 如果不是管理员则仅可以查看自己所教班级的数据
            List<String> accounts = teacherMapper.selectStudentAccountByTeacherAccount(currAccount);
            queryWrapper.in(!CollectionUtils.isEmpty(accounts), BattleUser::getAccount, accounts);
            queryWrapper.apply(CollectionUtils.isEmpty(accounts), "1 != 1");
        }

        // 查询对战记录
        battleUserMapper.selectPage(page, queryWrapper);

        // 获取所有对战ID
        List<BattleUser> battleUsers = page.getRecords();
        List<Long> ids = battleUsers.stream().map(BattleUser::getBattleId).collect(Collectors.toList());

        // 查询对战记录
        List<Battle> battles = this.list(new LambdaQueryWrapper<Battle>()
                .in(!CollectionUtils.isEmpty(ids), Battle::getId, ids)
                .apply(CollectionUtils.isEmpty(ids), "1 != 1"));
        // 构造结果集
        PageR<BattleListResp> pageR = new PageR<>();
        BeanUtils.copyProperties(page, pageR, "records");
        List<BattleListResp> collect = battleUsers.stream().map(battleUser -> {
            BattleListResp resp = new BattleListResp();
            resp.setAccount(battleUser.getAccount());
            User user = userService.getUserByAccount(battleUser.getAccount());
            resp.setName(user.getName());
            Optional.ofNullable(user.getAvatar()).ifPresent(id -> resp.setAvatarUrl(imageService.getImageById(id).getRemoteFileUrl()));
            battles.stream().filter(battle -> battle.getId().equals(battleUser.getBattleId())).findFirst().ifPresent(battle -> {
                List<BattleUser> thisBattleUsers = battleUserMapper.selectList(
                        new LambdaQueryWrapper<BattleUser>()
                                .eq(BattleUser::getBattleId, battleUser.getBattleId())
                                .orderByAsc(BattleUser::getConsumeTime));
                int rank = thisBattleUsers.stream().map(BattleUser::getAccount).collect(Collectors.toList()).indexOf(battleUser.getAccount());
                resp.setRank(rank + 1);
                resp.setId(battle.getId());
                resp.setIsWinner(battleUser.getAccount().equals(battle.getWinnerAccount()));
                resp.setRoomMaxNum(battle.getNumberSize());
                resp.setTime(battle.getCreateTime());
            });
            resp.setConsumeTime(battleUser.getConsumeTime());
            return resp;
        }).collect(Collectors.toList());
        pageR.setRecords(collect);
        return pageR;
    }

    @Override
    public BattleHisDetailResp getBattleDetailByTeacher(Long id){
        // 获取对战信息
        Battle battle = this.getById(id);
        if (Objects.isNull(battle)) {
            throw new EntityInvalidException("对战记录不存在");
        }

        // 获取对战成员信息
        List<BattleUser> battleUsers = battleUserMapper.selectList(
                new LambdaQueryWrapper<BattleUser>()
                        .eq(BattleUser::getBattleId, battle.getId())
                        .orderByAsc(BattleUser::getConsumeTime));

        // 构造成员信息
        List<BattleDetailResp> detailResps = battleUsers.stream().map(battleUser -> {
            BattleDetailResp resp = new BattleDetailResp();
            User user = userService.getUserByAccount(battleUser.getAccount());
            resp.setAccount(user.getAccount());
            resp.setUserId(String.valueOf(user.getId()));
            resp.setNickname(user.getNickname());
            resp.setIsFinished(true);
            resp.setRank(battleUsers.indexOf(battleUser) + 1);
            resp.setIsExit(battleUser.getIsExit() == 1);
            resp.setScore(battleUser.getTotalScore());
            resp.setSeconds(battleUser.getConsumeTime());
            Optional.ofNullable(user.getAvatar()).ifPresent(imageId -> resp.setAvatarUrl(imageService.getImageById(imageId).getRemoteFileUrl()));
            return resp;
        }).collect(Collectors.toList());

        BattleHisDetailResp resp = new BattleHisDetailResp();
        resp.setDetails(detailResps);
        return resp;
    }
}




